#include "test_byte.h"
#include "string.h"
#include "stdlib.h"

#include "esp_timer.h"
#include "esp_log.h"
#include "esp_sleep.h"

#include "driver/gpio.h"
#include "lua_user_model.h"

#define MODEL_NAME "byte"
//测试模板

static int lua_user_string(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    lua_pushstring(L,(*temp)->buff);
    return 1;
}
static int lua_user_get(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    int top=lua_gettop(L);
    int start=1,end=1;
    if(top==2){
        start=luaL_checkinteger(L,2);
        end=start;
    }else if(top==3){
        start=luaL_checkinteger(L,2);
        end=luaL_checkinteger(L,3);
    }
    if(start==end){
        lua_pushinteger(L,(int)((*temp)->buff[start-1]));
    }else{
        lua_newtable(L);
         int count=0;
        for(int i=start;i<end;i++){
            lua_pushnumber(L,count+1);
            count++;
            lua_pushnumber(L,(int)((*temp)->buff[i-1]));
            lua_rawset(L,-3);
        }
    }

    return 1;
}
//设置数据
// 使用 buf:set("123456")或者 buf:set(2,{1,2,3})
static int lua_user_set(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    int type=lua_type(L,2);
    int len=0;
    if(type==LUA_TSTRING){
        const char*str=luaL_checkstring(L,2);
        len=strlen(str);
        for(int i=0;i<len;i++){
            (*temp)->buff[i]=str[i];
        }
        (*temp)->buff[len]=0;
    }else{
        int index=luaL_checkinteger(L,2);
        len = luaL_len(L, 3);
        for(int i=0;i<len;i++){
            lua_pushnumber(L, i+1);
            lua_gettable(L, -2);
            type=lua_type(L,-1);
            int tempnum=0;
            if(type==LUA_TSTRING){
                const char*str= lua_tostring(L, -1);
                (*temp)->buff[index-1+i]=str[0];
            }else{
                tempnum = lua_tointeger(L, -1);
                (*temp)->buff[index-1+i]=(char)tempnum;
            }
            
            lua_pop(L, 1);
        }
        lua_pop(L, 2);
    }

    lua_pushinteger(L,len);
    return 1;
}

static int lua_user_len(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    lua_pushinteger(L,strlen((*temp)->buff));
    return 1; 
}

static int lua_user_size(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    lua_pushinteger(L,(*temp)->size);
    return 1; 
}
// //根据下标获取指定元素的值
// static int lua_user_index(lua_State *L){
//     user_byte**temp=(user_byte**)lua_touserdata(L,1);
//     int index=luaL_checkinteger(L,2);
//     if(index>(*temp)->size||index<1){
//         lua_pushinteger(L,-1);
//         return 1;
//     }
//     lua_pushinteger(L,(*temp)->buff[index-1]);
//     return 1;
// }
// tostring 方法 
static int lua_user_tostring(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    if((*temp)->buff!=NULL){
        lua_pushstring(L,(*temp)->buff);
    }else{
        lua_pushstring(L,"");
    }
    
    return 1;
}

// 执行 collectgarbage()函数会进行gc
static int lua_user_gc(lua_State *L){
    user_byte**temp=(user_byte**)lua_touserdata(L,1);
    free((*temp)->buff);
    free(*temp);
    return 0;
}

static const luaL_Reg lua_user_func[] ={ 
    {"set",lua_user_set},
    {"get",lua_user_get},
    {"len", lua_user_len}, 
    {"size", lua_user_size},
    {"string", lua_user_string},
    //{"__index", lua_user_index}, 
    {"__tostring", lua_user_tostring}, 
    {"__gc", lua_user_gc}, 
	{NULL, NULL}
};


// Timer.create('time1',22,call)
static int lua_create_new(lua_State *L){
     //创建一个对象指针放到stack里，返回给Lua中使用，userdata的位置-1
     int size=200;
     int top=lua_gettop(L);
     if(top==1){
        size=luaL_checkinteger(L,1);
     }
    char*buff=(char*)malloc(size);
    memset(buff,0,size);
    user_byte*bb=(user_byte*)malloc(sizeof(user_byte));
    bb->size=size;
    bb->buff=buff;
    user_byte**temp = (user_byte**)lua_newuserdata(L, sizeof(user_byte*));
    *temp=bb;
    //Lua->stack，得到全局元表位置-1,userdata位置-2
    luaL_getmetatable(L, MODEL_NAME);
    //将元表赋值给位置-2的userdata，并弹出-1的元表
    lua_setmetatable(L, -2);
    return 1;
}

static const luaL_Reg lua_user_constructor_funcs[] = {
    { "create", lua_create_new },
    { NULL, NULL }
};

int luaopen_user_byte_libs (lua_State *L) {
     //创建全局元表（里面包含了对LUA_REGISTRYINDEX的操作），元表的位置为-1
    luaL_newmetatable(L, MODEL_NAME);

    //将元表作为一个副本压栈到位置-1，原元表位置-2
    lua_pushvalue(L, -1);

    //设置-2位置元表的__index索引的值为位置-1的元表，并弹出位置-1的元表，原元表的位置为-1
    lua_setfield(L, -2, "__index");

    //将成员函数注册到元表中（到这里，全局元表的设置就全部完成了）
    luaL_setfuncs(L, lua_user_func, 0);
    //注册构造函数到新表中，并返回给Lua
    luaL_newlib(L, lua_user_constructor_funcs);
    return 1;
}